﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.Windows.Forms;

namespace AttrapeMoi
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        private Carte carte;
        private Timer timer = new Timer();
        private Timer timer_finPartie = new Timer();
        private Timer timer_pacman = new Timer();
        private int nb_bouge;
        private int nb_gendarme;
        private int nb_partie_bench;
        private int nb_partie_actuelle;
        private List<int> list_compte_tour;
        private String page_actuelle;
        private bool fini;
        private KeyboardState ancien_clavier;
        private MouseState souris_act;
        private String type_carte;
        private String mode_jeu;

        private SpriteFont font;
        private Sprite bouton_automatique;
        private Sprite bouton_duel;
        private Sprite bouton_classique;
        private Sprite bouton_hypercube3;
        private Sprite bouton_hypercube4;
        private Sprite bouton_tore;
        private Sprite bouton_demarrer;
        private Sprite bouton_bench;
        private Sprite selecteur1;
        private Sprite selecteur2;
        private Pacman pacman;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            this.IsMouseVisible = true;
            graphics.PreferredBackBufferHeight = 620;
            graphics.PreferredBackBufferWidth = 1280;
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            type_carte = "classique";
            mode_jeu = "auto";
            page_actuelle = "menu";
            list_compte_tour = new List<int>();
            nb_partie_bench = 100;
            nb_partie_actuelle = 0;
            carte = new Carte(type_carte, mode_jeu);
            fini = false;

            pacman = new Pacman();
            pacman.Initialize("voleur");

            timer.Tick += new EventHandler(bouge);
            timer_finPartie.Interval = 5000;
            timer_finPartie.Tick += new EventHandler(timer_finPartie_Tick);
            timer_pacman.Interval = 300;
            timer_pacman.Tick += new EventHandler(pacman.changeTex);

            bouton_automatique = new Sprite();
            bouton_automatique.Initialize("bouton_automatique");
            bouton_automatique.Position = new Vector2(18, 10);

            bouton_duel = new Sprite();
            bouton_duel.Initialize("bouton_duel");
            bouton_duel.Position = new Vector2(18, 15);

            bouton_classique = new Sprite();
            bouton_classique.Initialize("bouton_classique");
            bouton_classique.Position = new Vector2(32, 7);

            bouton_hypercube3 = new Sprite();
            bouton_hypercube3.Initialize("bouton_hypercube3");
            bouton_hypercube3.Position = new Vector2(32, 12);

            bouton_hypercube4 = new Sprite();
            bouton_hypercube4.Initialize("bouton_hypercube4");
            bouton_hypercube4.Position = new Vector2(32, 17);
            
            bouton_tore = new Sprite();
            bouton_tore.Initialize("bouton_tore");
            bouton_tore.Position = new Vector2(32, 22);

            bouton_demarrer = new Sprite();
            bouton_demarrer.Initialize("bouton_demarrer");
            bouton_demarrer.Position = new Vector2(38, 26);

            bouton_bench = new Sprite();
            bouton_bench.Initialize("bouton_bench");
            bouton_bench.Position = new Vector2(18, 20);

            selecteur1 = new Sprite();
            selecteur1.Initialize("select");

            selecteur2 = new Sprite();
            selecteur2.Initialize("select");
            
            base.Initialize();
        }

        void timer_finPartie_Tick(object sender, EventArgs e)
        {
            page_actuelle = "menu";
            timer_finPartie.Stop();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            font = Content.Load<SpriteFont>("font");
            bouton_automatique.LoadContent(Content);
            bouton_duel.LoadContent(Content);
            bouton_classique.LoadContent(Content);
            bouton_hypercube3.LoadContent(Content);
            bouton_hypercube4.LoadContent(Content);
            bouton_tore.LoadContent(Content);
            bouton_demarrer.LoadContent(Content);
            bouton_bench.LoadContent(Content);
            selecteur1.LoadContent(Content);
            selecteur2.LoadContent(Content);
            carte.LoadContent(Content);
            pacman.LoadContent(Content);
            // TODO: use this.Content to load your game content here
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
                this.Exit();

            KeyboardState clavier = Keyboard.GetState();
            MouseState souris = Mouse.GetState();
            // TODO: Add your update logic here
            switch (page_actuelle)
            {
                case "menu":
                    switch (mode_jeu)
                    {
                        case "auto":
                            selecteur1.Position = new Vector2(17, 10);
                            break;

                        case "duel":
                            selecteur1.Position = new Vector2(17, 15);
                            break;

                        case "benchmark":
                            selecteur1.Position = new Vector2(17, 20);
                            break;
                    }

                    switch (type_carte)
                    {
                        case "classique":
                            selecteur2.Position = new Vector2(31, 7);
                            break;

                        case "hypercube 3":
                            selecteur2.Position = new Vector2(31, 12);
                            break;

                        case "hypercube 4":
                            selecteur2.Position = new Vector2(31, 17);
                            break;

                        case "tore":
                            selecteur2.Position = new Vector2(31, 22);
                            break;
                    }

                    if (souris.LeftButton == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
                    {
                        if (souris.X > 378 && souris.X < 500)
                        {
                            if (souris.Y > 210 && souris.Y < 231)
                                mode_jeu = "auto";
                            else if (souris.Y > 315 && souris.Y < 336)
                                mode_jeu = "duel";
                            else if (souris.Y > 420 && souris.Y < 441)
                                mode_jeu = "benchmark";
                        }
                        else if (souris.X > 651 && souris.X < 873)
                        {
                            if (souris.Y > 147 && souris.Y < 168)
                                type_carte = "classique";
                            else if (souris.Y > 252 && souris.Y < 273)
                                type_carte = "hypercube 3";
                            else if (souris.Y > 357 && souris.Y < 378)
                                type_carte = "hypercube 4";
                            else if (souris.Y > 462 && souris.Y < 483)
                                type_carte = "tore";
                        }
                           
                        if (souris.X > 798 && souris.X < 798 + bouton_demarrer.Texture.Width && souris.Y > 546 && souris.Y < 567)
                        {
                            init();
                        }
                    }
                    break;

                case "partie":
                    if (!fini)
                    {
                        Vector2 positionVoleur = carte.Voleur;
                        int[,] matrice = carte.Matrice_adjacence;
                        int numCase = carte.getCase(positionVoleur.X, positionVoleur.Y).NumCase;

                        for (int i = 0; i < carte.Longueur_adjacence; i++)
                        {
                            if (matrice[i, numCase] == 1 && carte.getCase(i).Contenu1 == Contenu.gendarme && !carte.Type_actu)
                            {
                                fini = true;
                                timer.Stop();
                            }
                        }

                        if (clavier.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Space) && ancien_clavier.IsKeyUp(Microsoft.Xna.Framework.Input.Keys.Space))
                        {
                            page_actuelle = "menu";
                            if (pacman.Position != Vector2.Zero)
                            {
                                pacman.Position = Vector2.Zero;
                                timer_pacman.Stop();
                            }

                            fini = true;
                            if (nb_partie_actuelle > 0)
                            {
                                list_compte_tour.Clear();
                                nb_partie_actuelle = 0;
                            }
                            timer.Stop();
                        }

                        if (mode_jeu == "benchmark")
                        {
                            if (pacman.Position != Vector2.Zero)
                                pacman.Update(gameTime, 200, 200);
                            if (nb_bouge > 250)
                            {
                                fini = true;
                                timer.Stop();
                            }
                        }
                    }
                    else if (!timer_finPartie.Enabled)
                    {
                        if (mode_jeu == "benchmark")
                        {
                            nb_partie_actuelle++;
                            if (nb_partie_actuelle <= nb_partie_bench)
                            {
                                list_compte_tour.Add(nb_bouge);
                                init();
                            }
                            else
                                page_actuelle = "afficheDonneesBenchmark";
                        }
                        else
                            timer_finPartie.Start();
                    }
                    break;

                case "afficheDonneesBenchmark":
                    if (clavier.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Space) && ancien_clavier.IsKeyUp(Microsoft.Xna.Framework.Input.Keys.Space))
                    {
                        list_compte_tour.Clear();
                        nb_partie_actuelle = 0;
                        pacman.Position = Vector2.Zero;
                        timer_pacman.Stop();
                        page_actuelle = "menu";                       
                    }
                    break;
            }
            souris_act = souris;
            ancien_clavier = clavier;

            base.Update(gameTime);
        }

        private void init()
        {
            carte = new Carte(type_carte, mode_jeu);
            carte.LoadContent(Content);
            nb_bouge = 0;
            fini = false;
            nb_gendarme = carte.placeDepart();
            page_actuelle = "partie";
            if (mode_jeu == "benchmark")
                timer.Interval = 1;
            else
                timer.Interval = 500;

            timer.Start();
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);

            spriteBatch.Begin();
            /*
            int[,] matrice = carte.Matrice_adjacence;

            for (int i = 0; i < carte.Longueur_adjacence; i++)
                for (int j = 0; j < carte.Longueur_adjacence; j++)
                {
                    string texte_prochain = matrice[j, i].ToString();
                    spriteBatch.DrawString(font, texte_prochain, new Vector2(i*15, j*15), Color.Black);
                }
            */
            switch (page_actuelle)
            {
                case "menu":
                    bouton_automatique.Draw(spriteBatch);
                    bouton_classique.Draw(spriteBatch);
                    bouton_duel.Draw(spriteBatch);
                    bouton_hypercube3.Draw(spriteBatch);
                    bouton_hypercube4.Draw(spriteBatch);
                    bouton_tore.Draw(spriteBatch);
                    bouton_demarrer.Draw(spriteBatch);
                    bouton_bench.Draw(spriteBatch);
                    selecteur2.Draw(spriteBatch);
                    selecteur1.Draw(spriteBatch);
                    break;

                case "partie":
                    if (mode_jeu != "benchmark")
                        carte.Draw(spriteBatch, GraphicsDevice);
                    else
                    {
                        
                        Texture2D tex_barre = new Texture2D(GraphicsDevice, 550, 21);
                        Texture2D tex_barre2 = new Texture2D(GraphicsDevice, (550 * (nb_partie_actuelle+1)) / nb_partie_bench, 19);
                        Color[] tab_color1 = new Color[550 * 21];
                        Color[] tab_color2 = new Color[(19 * (550 * (nb_partie_actuelle+1) / nb_partie_bench))];
                        for (int i = 0; i < tab_color1.Length; i++)
                            tab_color1[i] = Color.DarkRed;
                        for (int i = 0; i < tab_color2.Length; i++)
                            tab_color2[i] = Color.Red;

                        tex_barre.SetData(tab_color1);
                        tex_barre2.SetData(tab_color2);
                        spriteBatch.Draw(tex_barre, new Vector2((Window.ClientBounds.Width - tex_barre.Width) / 2, (Window.ClientBounds.Height - tex_barre.Height) / 2), Color.White);
                        spriteBatch.Draw(tex_barre2, new Vector2((Window.ClientBounds.Width - tex_barre2.Width) / 2, (Window.ClientBounds.Height - tex_barre2.Height) / 2), Color.White);

                        if (pacman.Position == Vector2.Zero)
                        {
                            pacman.Position = new Vector2(15, 13);
                            pacman.Direction = new Vector2(1, 0);
                            timer_pacman.Start();
                        }

                        pacman.Draw(spriteBatch);
                    }
                    break;

                case "afficheDonneesBenchmark":
                    int moy = 0, min = 210, nb = 0, moy2 = 0;
                    for (int i = 0; i < list_compte_tour.Count; i++)
                    {
                        if (list_compte_tour[i] < 250)
                        {
                            moy += list_compte_tour[i];
                            nb++;
                        }
                        moy2 += list_compte_tour[i];
                        if (min > list_compte_tour[i])
                            min = list_compte_tour[i];

                        String text = "partie " + (i + 1) + " : " + list_compte_tour[i];
                        spriteBatch.DrawString(font, text, new Vector2(20 + (int)(i/45)*140, (i%45) * 13), Color.White);
                    }

                    String texte = "moyenne sans les max: " + (moy / nb);
                    spriteBatch.DrawString(font, texte, new Vector2(450, 200), Color.White);
                    texte = "moyenne : " + (moy2 / list_compte_tour.Count);
                    spriteBatch.DrawString(font, texte, new Vector2(450, 225), Color.White);
                    texte = "minimum : " + min;
                    spriteBatch.DrawString(font, texte, new Vector2(450, 250), Color.White);
                    break;
            }            
            
            // TODO: Add your drawing code here
            spriteBatch.End();
            base.Draw(gameTime);
        }


        protected void bouge(object sender, EventArgs e)
        {
            bouge();
        }

        protected void bouge()
        {
            carte.Update(souris_act);
            nb_bouge++;
        }
    }
}
